分享人:左少华
目录
1.背景介绍
2.知识剖析
3.常见问题
4.解决方案
5.编码实战
6.扩展思考
7.参考文献
8.更多讨论
路由(route),几乎所有的MVC(VM)框架都应该具有的特性,因为它是前端构建单页面应用(SPA)必不可少的组成部分。
对于angular而言,自然也有内置的路由模块-ngRoute。但由于功能的局限性,往往不能满足开发需求。于是,AngularUI团队基于ngRoute开发了第三方模块-UI-Router。
UI-Router注入与配置
和ngRoute一样,UI-Router首先需要作为依赖注入应用
angular.module("myApp", ["ui.router"]).config(function($stateProvider){
$stateProvider.state(stateName, stateConfig);
})
html标签中设置视图插入位置: 如
UI-router基本参数
$stateProvider:配置应用状态
用法:$stateProvider.state(stateName, stateConfig)
stateConfig:对象,该路由的具体配置项
url:默认相对路径(以^开头的是绝对路径)
views:每个子视图可以包含自己的模板、控制器和预载入数据。设置多视图。如果在单个状态不需要此属性。
template: HTML字符串或者返回HTML字符串的函数(一般用templateUrl)
templateUrl: HTML模板的路径或者返回HTML模板路径的函数
controller、controllerProvider:指定任何已经被注册的控制器或者一个作为控制器的函数
resolve:预载入依赖或数据,注入到控制器中。
onEnter, onExit:路由进入OR退出时执行的函数
1.views:当一个页面需要嵌入多个视图时,可以配置参数,这里介绍相对路径的配置,绝对路径用@的形式,可查看官方文档
html
$stateProvider .state('report',{ views: { 'filters': { templateUrl: 'report-filters.html',//指定模板 controller: function($scope){ ... controller stuff just for filters view ... }//控制器 }, 'tabledata': { templateUrl: 'report-table.html', controller: function($scope){ ... controller stuff just for tabledata view ... } }, 'graph': { templateUrl: 'report-graph.html', controller: function($scope){ ... controller stuff just for graph view ... } } } })
resolve:向该路由控制器注入依赖或数据,格式{string|function}
resolve: {promiseObj: function($http){ return $http({method: 'GET', url: '/someUrl'}) .then (function (data) { return doSomeStuffFirst(data); }); }},
//在controller中注入promiseObj获取值 controller: function($scope,promiseObj){ $scope.items = promiseObj.data.items; }
data:注入自定义数据
onEnter 和 onExit 回调函数,在进入该路由和离开该路由时触发
//这个做登陆验证也不错,进入需要登陆的模块时,检测登陆状态,未登陆就跳转,做一些弹窗也可以
$stateProvider.state("contacts", {
template: ' {{title}}
',
resolve: { title: 'My Contacts' },
controller: function($scope, title){
$scope.title = title;
},
onEnter: function(title){
if (title) { ... do something ... }
},
onExit: function(title){
if (title) { ... do something ... }
}
})
1、路由间参数如何传递?
2、嵌套路由父子关系如何定义?
1、路由间参数如何传递?
一、通过url传递:url中传递参数也有好几种形式,如(ui-sref="a({}),$state.go('a',({}))")
url:"/contacts/:contactId" //url中传入参数为 /contacts/42 url: "/contacts/{contactId}"
//若为查询参数 url: "/contacts?myParam" //将匹配url的“/ contacts?myParam = value” url: "/contacts?myParam1&myParam2" //will match to url of "/contacts?myParam1=value1&myParam2=wowcool"
二、通过params属性设置
.state('contacts', {
url: "/contacts",
params: {
param1: null
},
templateUrl: 'contacts.html'
})
View Contacts or $state.go('contacts', {param1: value1})
2、嵌套路由父子关系如何定义?
$stateProvider
.state('contacts.list', {});//点标记法(推荐)
$stateProvider //parent属性
.state({
name: 'list', // 状态名也可以直接在配置里指定
parent: 'contacts' // 父路由的状态名
});
.state('field.moduleDetail', { url: '/moduleEdit?id', templateUrl: 'Pages/moduleEdit.html', controller: 'moduleEditController', controllerAs: 'vm', }) ui-sref="field.moduleDetail({id:item.id})" //url 中http://admin.luoboduo.com/#/panel/moduleEdit?id=1
.state('field.companyList', { //url:http://admin.luoboduo.com/#/panel/professionMsg (field URL为panel) url: '/companyMsg', templateUrl: 'Pages/companyMsg.html', controller: 'CompanyListController', controllerAs: 'vm' })
UI-router工作原理?
路由对于前端MVC(VM)而言,就是将hash值(#xxx)与一系列的路由规则进行查找匹配,匹配出一个符合条件的规则,然后根据这个规则,进行数据的获取,以及页面的渲染。
大致过程
1.创建路由规则
.state('home', {
url: '/abc',
template: 'hello world'
});
首先,$urlRouterProvider创建并存储一个state对象,里面包含着该路由规则的所有配置信息。然后,调用$urlRouterProvider.when(...)方法,进行路由的注册(之前是路由的创建)
2.路由查找匹配
(1)angular 在刚开始的$digest时,$rootScope会触发$locationChangeSuccess事件(angular在每次浏览器hash change的时候也会触发$locationChangeSuccess事件)
(2)ui.router 监听了$locationChangeSuccess事件,于是开始通过遍历一系列rules,进行路由查找匹配
(3)当匹配到路由后,就通过$state.transitionTo(state,...),跳转激活对应的state
(4)最后,完成数据请求和模板的渲染
当我们访问http://xxxx#/abc的时候,这个路由规则被匹配到,对应的模板会被填到某个div[ui-view]中
一般路由要对rules进行遍历,但ui-router进行了优化:
ui.router在创建路由时,会实例化一个对应的state对象,并存储起来(states集合里面),每一个state对象都有一个state.name进行唯一标识(如:'home')
当通过ui-sref(会调用$state.go())指令或直接通过$state.go()跳转时,ui-sref="home"指令会给对应的dom添加click事件,然后根据state.name,直接跳转到对应的state,跳转到对应的state之后,ui.router会改变hash,所以触发’$locationChangeSuccess'事件,然后执行回调,在回调中通过一个判断代码规避循环rules
所以尽量避免直接使用href="#/xxx"来改变hash,然后跳转到对应state。这么做将进行rules遍历,浪费性能
参考一:angular中的路由
参考二:uiroueter官方文档
uiRouter中还要很多对应事件,了解之后在项目中很有帮助
state事件
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){ ... })
$rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams){ ... })
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ ... })
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){ ... })
view事件
View被加载但是DOM树构建之前时:
$scope.$on('$viewContentLoading', function(event, viewConfig){ ... });
View被加载而且DOM树构建完成时:
$scope.$on('$viewContentLoaded', function(event){ ... });
感谢大家观看
BY :李绍博 | 左少华